package com.uppfind.framework.controller;

import com.uppfind.framework.core.exception.NotFoundException;
import com.uppfind.framework.core.message.ResponseMessage;
import com.uppfind.framework.dao.api.common.params.DeleteParam;
import com.uppfind.framework.dao.api.common.params.QueryParam;
import com.uppfind.framework.dao.api.common.params.UpdateParam;
import com.uppfind.framework.service.GenericService;
import com.uppfind.framework.utils.ClassUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

/**
 * 通用控制器,此控制器实现了通用的增删改查功能
 * 需要提供一个实现了{@link GenericService}接口的实现类
 * Created by xuliugen on 2017/6/29.
 */
public abstract class GenericController<PO, PK> {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 获取此Controller需要的服务类,由子类实现
     * @return 通用服务类
     */
    protected abstract GenericService<PO, PK> getService();

    /**
     * 获取PO的类型
     * @return PO类型
     */
    protected final Class<PO> getPOType() {
        return (Class<PO>) ClassUtils.getGenericType(this.getClass(), 0);
    }

    /**
     * 获取PK(主键)的类型
     * @return PK(主键)类型
     */
    protected final Class<PK> getPKType() {
        return (Class<PK>) ClassUtils.getGenericType(this.getClass(), 1);
    }

    /**
     * 查询列表,并返回查询结果,不分页
     * @param param 查询参数 {@link QueryParam}
     * @param param
     * @return 查询结果, 如果参数指定了分页(默认指定)将返回格式如:{total:数据总数,data:[{}]}的数据.否则返回格式[{}]
     */
    @RequestMapping(method = RequestMethod.GET)
    public ResponseMessage list(QueryParam param) {
        // 获取条件查询
        Object data;
        if (!param.isPaging()) { //不分页
            data = getService().select(param);
        } else {
            data = getService().selectPager(param);
        }
        return ResponseMessage.ok(data)
                .include(getPOType(), param.getIncludes())
                .exclude(getPOType(), param.getExcludes())
                .onlyData();
    }

    /**
     * 根据id（主键）查询数据
     * @param id 主键
     * @return 请求结果
     * @throws NotFoundException 要查询的数据不存在
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseMessage info(@PathVariable("id") PK id) {
        PO po = getService().selectByPk(id);

        if (po == null) {
            throw new NotFoundException("data is not found!");
        }
        return ResponseMessage.ok(po);
    }

    /**
     * 根据查询条件，查询数据数量
     * @param param 查询条件
     * @return 请求结果
     */
    @RequestMapping(value = "/total", method = RequestMethod.GET)
    public ResponseMessage total(QueryParam param) {
        // 获取条件查询
        return ResponseMessage.ok(getService().total(param));
    }

    /**
     * 请求添加数据，请求必须以POST方式
     * @param po 请求添加的对象
     * @return 被添加数据的主键值
     * @throws javax.validation.ValidationException 验证数据格式错误
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public ResponseMessage add(@RequestBody PO po) {
        PK pk = getService().insert(po);
        return ResponseMessage.created(pk);
    }

    /**
     * 请求删除指定id的数据，请求方式为DELETE，使用rest风格，如请求 /delete/1 ，将删除id为1的数据
     * @param id 要删除的id标识
     * @return 删除结果
     * @throws NotFoundException 要删除的数据不存在
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public ResponseMessage delete(@PathVariable("id") PK id) {
        int number = getService().delete(new DeleteParam<PK>().build(id));
        return ResponseMessage.ok(number);
    }

    @RequestMapping(value = "/byIds", method = RequestMethod.DELETE)
    public ResponseMessage deleteByIds(@RequestBody DeleteParam<PK> param) {
        int number = getService().delete(param);
        return ResponseMessage.ok(number);
    }

    /**
     * 根据主键修改数据
     * @param po 修改数据的实体对象
     * @throws NotFoundException 要修改的数据不存在
     */
    @RequestMapping(value = "/byId", method = RequestMethod.PUT)
    public ResponseMessage updateById(@RequestBody PO po) {
        int number = getService().update(new UpdateParam<PO>().build(po));
        return ResponseMessage.ok(number);
    }

    /**
     * Request URL:{"po":{"id":"1","rname":"xuliugen","password":"aaaaaaaa","status":0}}
     * 根据更新参数修改数据
     * @param param 要修改的数据
     * @return 请求结果
     * @throws NotFoundException 要修改的数据不存在
     */
    @RequestMapping(method = RequestMethod.PUT)
    public ResponseMessage update(@RequestBody UpdateParam<PO> param) {
        int number = getService().update(param);
        return ResponseMessage.ok(number);
    }

}
